using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Resources;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using LoginScreenConverter;
using csammisrun.shaim;

namespace LoginScreenConverter
{
  class SomethingToBitmapConverter : IValueConverter
  {
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      BitmapImage bimg = new BitmapImage();
      bimg.BeginInit();
      bimg.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
      if (value is System.IO.Stream)
      {
        if (value == null)
        {
          return null;
        }

        bimg.StreamSource = value as System.IO.Stream;
      }
      else
      {
        if (String.IsNullOrEmpty((string)value))
        {
          return null;
        }
        bimg.UriSource = new Uri((string)value);
      }
      bimg.EndInit();

      return bimg;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      throw new NotImplementedException();
    }

    #endregion
  }

  public class ProtocolPluginRenderer
  {
    public ProtocolPluginRenderer()
    { }

    private IProtocolPlugin _pluginbacking;
    public IProtocolPlugin Plugin
    {
      get { return _pluginbacking; }
      set { _pluginbacking = value; }
    }

    public System.IO.Stream DisplayIcon
    {
      get
      {
        if (_pluginbacking != null)
        {
          System.IO.Stream retval = _pluginbacking.DisplayIcon;
          retval.Position = 0;
          return retval;
        }
        else
        {
          return null;
        }
      }
    }

    private string _message = "Starting up";
    public string Message
    {
      get { return _message; }
      set { _message = value; }
    }
  }
}

namespace DefaultUI
{
  /// <summary>
  /// Interaction logic for LoginScreen.xaml
  /// </summary>

  public partial class LoginScreen : Window
  {
    private ICore _core = null;
    private bool _shutdownonclose = true;
    private int _connectedplugins = 0;

    public LoginScreen()
    {
      InitializeComponent();
    }

    public LoginScreen(ICore core)
    {
      InitializeComponent();
      this.Closing += new CancelEventHandler(LoginScreen_Closing);

      _core = core;
      _core.AccountListModified += new AccountListModifiedHandler(RenderAccountList);
      RenderAccountList();
    }

    private void LoginScreen_Closing(object sender, CancelEventArgs e)
    {
      if (_core != null)
      {
        if (_shutdownonclose)
        {
          _core.Shutdown();
        }
      }
    }

    private void AccountsClicked(object sender, RoutedEventArgs e)
    {
      PreferenceScreen prefscreen = DefaultUI.PreferenceScreen;
      Uri baseuri = BaseUriHelper.GetBaseUri(prefscreen as NavigationWindow);
      Uri realuri = new Uri(baseuri, ShaimPreferenceConstants.Home);
      prefscreen.Navigate(realuri);
      prefscreen.ShowElement();
    }

    void LoginScreen_Closed(object sender, EventArgs e)
    {
      DefaultUI.PreferenceScreen = null;
    }

    private void SignInClicked(object sender, RoutedEventArgs e)
    {
      ShaimAccount account = AccountList.SelectedItem as ShaimAccount;
      if (Password.Password != account.Password)
      {
        MessageBox.Show(this, "Incorrect password", this.Title, MessageBoxButton.OK,
          MessageBoxImage.Hand);
        return;
      }

      _core.ActiveAccount = account;

      _connectedplugins = 0;
      foreach (ShaimProtocol proto in account.Protocols)
      {
        // Load up a plugin for each one and load its data
        proto.Plugin = _core.LoadProtocolPlugin(proto.Info.Plugin, proto.Username);
        if (proto.Plugin == null)
        {
          continue;
        }

        ProtocolPluginRenderer renderer = new ProtocolPluginRenderer();
        renderer.Plugin = proto.Plugin;

        if (!proto.Plugin.Connected)
        {
          proto.Plugin.Username = proto.Username;
          proto.Plugin.Password = _core.DecryptPassword(proto.Password, account.Password);
          if (proto.Plugin.Password == "")
          {
            // Prompt for a password  (but some protocols don't require a passphrase...)
          }
          proto.Plugin.SetCustomData(proto.Info.CustomDataTypes);
          if (proto.Plugin is IUserInfoPlugin)
          {
            (proto.Plugin as IUserInfoPlugin).SetUserInfo(
              account.UserInfo, System.Text.Encoding.ASCII);
          }

          // Register this as a handler for protocol plugin messages relating to connections
          _core.RegisterAsHandler(DefaultUI.Ref,
            ShaimIncomingEventID.ProtocolStatusMessage,
            new ProtocolStatusMessageHandler(this.ProtocolStatusMessage));
          _core.RegisterAsHandler(DefaultUI.Ref,
            ShaimIncomingEventID.ProtocolErrorMessage,
            new ProtocolErrorMessageHandler(this.ProtocolErrorMessage));
          _core.RegisterAsHandler(DefaultUI.Ref,
            ShaimIncomingEventID.ConnectionComplete,
            new ConnectionCompleteHandler(this.ProtocolConnectionComplete));
          _core.RegisterAsHandler(DefaultUI.Ref,
            ShaimIncomingEventID.ConnectionFailed,
            new ConnectionFailedHandler(this.ProtocolConnectionFailed));
        }
        StatusListBox.Items.Add(renderer);
      }

      AccountListPanel.Visibility = Visibility.Hidden;
      StatusListPanel.Visibility = Visibility.Visible;

      foreach (ProtocolPluginRenderer renderer in StatusListBox.Items)
      {
        if (!renderer.Plugin.Connected)
        {
          renderer.Plugin.Connect();
        }
        else
        {
          _shutdownonclose = false;
          _connectedplugins++;
          renderer.Message = "Already logged in";
        }
      }

      StatusListBox.Items.Refresh();
    }

    private void ProtocolStatusMessage(IProtocolPlugin plugin, ref string message)
    {
      string msg = message;
      AnonInvoker invoker = delegate
      {
        foreach (ProtocolPluginRenderer renderer in StatusListBox.Items)
        {
          if (renderer.Plugin == plugin)
          {
            renderer.Message = msg;
            StatusListBox.Items.Refresh();
            break;
          }
        }
      };

      this.Dispatcher.BeginInvoke(DispatcherPriority.Input, invoker);
    }

    private void ProtocolErrorMessage(IProtocolPlugin plugin, ref string message)
    {
      string msg = message;
      AnonInvoker invoker = delegate
      {
        foreach (ProtocolPluginRenderer renderer in StatusListBox.Items)
        {
          if (renderer.Plugin == plugin)
          {
            // Alert the user of a problem with some sort of cue
            renderer.Message = msg;
            StatusListBox.Items.Refresh();
            plugin.Disconnect();
            break;
          }
        }
      };

      this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, invoker);
    }

    private void ProtocolConnectionComplete(IProtocolPlugin plugin)
    {
      AnonInvoker invoker = delegate
      {
        _shutdownonclose = false;
        _connectedplugins++;

        foreach (ProtocolPluginRenderer renderer in StatusListBox.Items)
        {
          if (renderer.Plugin == plugin)
          {
            renderer.Message = "Logged in";
            StatusListBox.Items.Refresh();
            break;
          }
        }

        if (_connectedplugins == StatusListBox.Items.Count)
        {
          this.Close();
        }
      };

      // Show the buddy list plugin, it may already have items
      DefaultUI.BuddyList.ShowElement();

      this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, invoker);
    }

    private void ProtocolConnectionFailed(IProtocolPlugin plugin, ref string reason)
    {
      string msg = reason;
      AnonInvoker invoker = delegate
      {
        // Render the message into the right label
        foreach (ProtocolPluginRenderer renderer in StatusListBox.Items)
        {
          if (renderer.Plugin == plugin)
          {
            // Alert the user of a problem with some sort of cue
            renderer.Message = msg;
            StatusListBox.Items.Refresh();
            plugin.Disconnect();
            break;
          }
        }
      };

      this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, invoker);
    }

    private void RenderAccountList()
    {
      AccountList.ItemsSource = _core.GetAccountList();
      //AccountList.Items.Clear();
      //foreach (ShaimAccount account in accounts)
      //{
      //  AccountList.Items.Insert(0, account);
      //}

      AccountList.SelectedIndex = 0;

      SignInButton.IsEnabled = (AccountList.Items.Count != 0);
    }

    public void ShowElement()
    {
      this.Visibility = Visibility.Visible;
    }

    public void HideElement()
    {
      this.Visibility = Visibility.Hidden;
    }
  }
}